package com.lib.framework.utils

import android.content.Context
import android.net.ConnectivityManager
import android.net.NetworkInfo
import android.net.wifi.WifiManager
import android.telephony.TelephonyManager
import androidx.annotation.RequiresPermission
import com.lib.framework.manager.ContextManager
import java.net.InetAddress
import java.net.NetworkInterface
import java.net.SocketException

/**
 * Copyright (C), 2020-2020, 享物说
 * FileName: NetUtil
 * Author: keanbin
 * Date: 2020-02-06 09:44
 * Description: 网络工具类
 * History:
 * <author> <time> <version> <desc>
 * 作者姓名 修改时间 版本号 描述
 */
class NetUtil {

    companion object {

        /**
         * 获取网络状态连接
         *
         * @return
         */
        fun getNetworkType(context: Context): String {
            var strNetworkType = ""
            val manager =
                context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
            val networkInfo = manager.activeNetworkInfo
            /*  NetworkInfo networkInfo = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE).getActiveNetworkInfo();*/
            if (networkInfo != null && networkInfo.isConnected) {
                if (networkInfo.type == ConnectivityManager.TYPE_WIFI) {
                    strNetworkType = "wifi"
                } else if (networkInfo.type == ConnectivityManager.TYPE_MOBILE) {
                    when (networkInfo.subtype) {
                        //如果是2g类型
                        TelephonyManager.NETWORK_TYPE_GPRS // 联通2g
                            , TelephonyManager.NETWORK_TYPE_CDMA // 电信2g
                            , TelephonyManager.NETWORK_TYPE_EDGE // 移动2g
                            , TelephonyManager.NETWORK_TYPE_1xRTT, TelephonyManager.NETWORK_TYPE_IDEN -> strNetworkType =
                            "2G"
                        //如果是3g类型
                        TelephonyManager.NETWORK_TYPE_EVDO_A // 电信3g
                            , TelephonyManager.NETWORK_TYPE_UMTS, TelephonyManager.NETWORK_TYPE_EVDO_0, TelephonyManager.NETWORK_TYPE_HSDPA, TelephonyManager.NETWORK_TYPE_HSUPA, TelephonyManager.NETWORK_TYPE_HSPA, TelephonyManager.NETWORK_TYPE_EVDO_B, TelephonyManager.NETWORK_TYPE_EHRPD, TelephonyManager.NETWORK_TYPE_HSPAP -> strNetworkType =
                            "3G"
                        //如果是4g类型
                        TelephonyManager.NETWORK_TYPE_LTE -> strNetworkType = "4G"
                        else -> {
                        }
                    }
                }

                return strNetworkType
            }

            return "none"
        }


        /**
         * 判断网络是否连接
         *
         * @return true/false
         */
        fun isNetConnected(context: Context): Boolean {
            val connectivity =
                context.getSystemService(Context.CONNECTIVITY_SERVICE) as? ConnectivityManager
            if (connectivity != null) {
                val info = connectivity.activeNetworkInfo
                if (info != null && info.isConnected) {
                    if (info.state == NetworkInfo.State.CONNECTED) {
                        return true
                    }
                }
            }
            return false
        }

        /**
         * Return the MAC address.
         *
         * Must hold
         * `<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />`,
         * `<uses-permission android:name="android.permission.INTERNET" />`
         *
         * @return the MAC address
         */
        fun getMacAddress(): String? {
            return getMacAddress("")
        }

        fun getMacAddress(vararg excepts: String): String? {
            var macAddress = getMacAddressByWifiInfo()
            if (isAddressNotInExcepts(macAddress, *excepts)) {
                return macAddress
            }
            macAddress = getMacAddressByNetworkInterface()
            if (isAddressNotInExcepts(macAddress, *excepts)) {
                return macAddress
            }
            macAddress = getMacAddressByInetAddress()
            if (isAddressNotInExcepts(macAddress, *excepts)) {
                return macAddress
            }
            macAddress = getMacAddressByFile()
            return if (isAddressNotInExcepts(macAddress, *excepts)) {
                macAddress
            } else ""
        }


        private fun isAddressNotInExcepts(address: String?, vararg excepts: String): Boolean {
            if (address.isNullOrEmpty()) return false

            if (excepts == null || excepts.size == 0) {
                return "02:00:00:00:00:00" != address
            }
            for (filter in excepts) {
                if (address == filter) {
                    return false
                }
            }
            return true
        }

        private fun getMacAddressByWifiInfo(): String? {
            try {
                val context = ContextManager.applicationContext
                val wifi = context.getSystemService(Context.WIFI_SERVICE) as WifiManager
                if (wifi != null) {
                    val info = wifi.connectionInfo
                    if (info != null) return info.macAddress
                }
            } catch (e: Exception) {
                e.printStackTrace()
            }

            return "02:00:00:00:00:00"
        }

        private fun getMacAddressByNetworkInterface(): String? {
            try {
                val nis = NetworkInterface.getNetworkInterfaces()
                while (nis.hasMoreElements()) {
                    val ni = nis.nextElement()
                    if (ni == null || !ni.name.equals("wlan0", ignoreCase = true)) continue
                    val macBytes = ni.hardwareAddress
                    if (macBytes != null && macBytes.isNotEmpty()) {
                        val sb = StringBuilder()
                        for (b in macBytes) {
                            sb.append(String.format("%02x:", b))
                        }
                        return sb.substring(0, sb.length - 1)
                    }
                }
            } catch (e: Exception) {
                e.printStackTrace()
            }

            return "02:00:00:00:00:00"
        }

        private fun getMacAddressByInetAddress(): String? {
            try {
                val inetAddress = getInetAddress()
                if (inetAddress != null) {
                    val ni = NetworkInterface.getByInetAddress(inetAddress)
                    if (ni != null) {
                        val macBytes = ni.hardwareAddress
                        if (macBytes != null && macBytes.size > 0) {
                            val sb = StringBuilder()
                            for (b in macBytes) {
                                sb.append(String.format("%02x:", b))
                            }
                            return sb.substring(0, sb.length - 1)
                        }
                    }
                }
            } catch (e: Exception) {
                e.printStackTrace()
            }

            return "02:00:00:00:00:00"
        }

        private fun getInetAddress(): InetAddress? {
            try {
                val nis = NetworkInterface.getNetworkInterfaces()
                while (nis.hasMoreElements()) {
                    val ni = nis.nextElement()
                    // To prevent phone of xiaomi return "10.0.2.15"
                    if (!ni.isUp) continue
                    val addresses = ni.inetAddresses
                    while (addresses.hasMoreElements()) {
                        val inetAddress = addresses.nextElement()
                        if (!inetAddress.isLoopbackAddress) {
                            val hostAddress = inetAddress.hostAddress
                            if (hostAddress.indexOf(':') < 0) return inetAddress
                        }
                    }
                }
            } catch (e: SocketException) {
                e.printStackTrace()
            }

            return null
        }

        private fun getMacAddressByFile(): String? {
            var result = ShellUtils.execCmd("getprop wifi.interface", false)
            if (result.result === 0) {
                val name = result.successMsg
                if (name != null) {
                    result = ShellUtils.execCmd("cat /sys/class/net/$name/address", false)
                    if (result.result === 0) {
                        val address = result.successMsg
                        if (address != null && address.isNotEmpty()) {
                            return address
                        }
                    }
                }
            }
            return "02:00:00:00:00:00"
        }
    }
}